﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using CodedUITestExtensions.Tree;
using Microsoft.VisualStudio.TestTools.UITest.Extension;
using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.WpfControls;

namespace CodedUITestExtensions
{
    /// <summary>
    /// Extensions for WpfTree.
    /// </summary>
    public static class WpfTreeExtensions
    {
        /// <summary>
        /// Forms the visual tree as a tree node containing text.
        /// </summary>
        /// <param name="tree">WpfTree.</param>
        /// <returns>Visual tree.</returns>
        public static SimpleTree FormVisualTree(this WpfTree tree)
        {
            if (tree == null)
            {
                throw new ArgumentNullException("tree");
            }

            var simpleTree = new SimpleTree();
            IEnumerable<WpfTreeItem> treeItems = tree.Nodes.Cast<WpfTreeItem>();
            foreach (WpfTreeItem treeItem in treeItems)
            {
                TreeNode treeNode = simpleTree.Children.Add(treeItem.GetTreeItemText());
                if (treeItem.HasChildNodes)
                {
                    if (!treeItem.Expanded)
                    {
                        Mouse.DoubleClick(treeItem);
                        //treeItem.Expanded = true;
                    }
                    Traverse(treeNode, treeItem);
                }
            }

            return simpleTree;
        }

        /// <summary>
        /// Finds WpfTreeItem according to the node in the visual tree.
        /// </summary>
        /// <param name="tree">WpfTree.</param>
        /// <param name="node">Tree node.</param>
        /// <returns>WpfTreeItem.</returns>
        public static WpfTreeItem FindTreeItem(this WpfTree tree, TreeNode node)
        {
            if (tree == null)
            {
                throw new ArgumentNullException("tree");
            }
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            var nodePath = new List<string>();
            while (node != null)
            {
                nodePath.Insert(0, node.Value);
                node = node.Parent;
            }

            WpfTreeItem treeItem = FindFirstLevelChildren(tree, nodePath[0]);
            if (treeItem != null)
            {
                for (int i = 1; i < nodePath.Count; ++i)
                {
                    treeItem = FindFirstLevelChildren(treeItem, nodePath[i]);
                    if (treeItem == null)
                    {
                        break;
                    }
                }
            }
            return treeItem;
        }

        /// <summary>
        /// Finds the WpfTreeItem by the value of the node.
        /// </summary>
        /// <param name="tree">WpfTree.</param>
        /// <param name="nodeValue">Tree node text.</param>
        /// <returns>WpfTreeItem.</returns>
        public static WpfTreeItem FindTreeItem(this WpfTree tree, string nodeValue)
        {
            return FindFirstLevelChildren(tree, nodeValue);
        }

        /// <summary>
        ///  Finds first WpfTreeItem by the value of the node.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <param name="nodeValue">Tree node text.</param>
        /// <returns>WpfTreeItem.</returns>
        private static WpfTreeItem FindFirstLevelChildren(WpfControl parent, string nodeValue)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }
            if (nodeValue == null)
            {
                throw new ArgumentNullException("nodeValue");
            }

            WpfTreeItem resultItem = null;
            int instance = 1;
            var treeItem = GetTreeItem(parent, instance);
            while (treeItem.TryFind() && (treeItem.ParentNode == parent))
            {
                if (treeItem.GetTreeItemText().Equals(nodeValue))
                {
                    resultItem = treeItem;
                    break;
                }
                ++instance;
                treeItem = GetTreeItem(parent, instance);
            }
            return resultItem;
        }

        /// <summary>
        /// Expands all tree nodes.
        /// </summary>
        /// <param name="tree">WpfTree.</param>
        public static void ExpandAllNodes(this WpfTree tree)
        {
            if (tree == null)
            {
                throw new ArgumentNullException("tree");
            }
            ExpandTraverse(tree.Nodes.Cast<WpfTreeItem>());
        }

        private static void Traverse(TreeNode treeNode, WpfTreeItem parentTreeItem)
        {
            if (treeNode == null)
            {
                throw new ArgumentNullException("treeNode");
            }
            if (parentTreeItem == null)
            {
                throw new ArgumentNullException("parentTreeItem");
            }

            IEnumerable<WpfTreeItem> treeItems = parentTreeItem.Nodes.Cast<WpfTreeItem>();
            foreach (WpfTreeItem treeItem in treeItems)
            {
                TreeNode addedTreeNode = treeNode.Children.Add(treeItem.GetTreeItemText());
                if (treeItem.HasChildNodes)
                {
                    if (!treeItem.Expanded)
                    {
                        Mouse.DoubleClick(treeItem);
                        //treeItem.Expanded = true;
                    }
                    Traverse(addedTreeNode, treeItem);
                }
            }
        }


        private static void ExpandTraverse(IEnumerable<WpfTreeItem> treeItems) 
        {
            foreach (WpfTreeItem treeItem in treeItems)
            {
                if (treeItem.HasChildNodes)
                {
                    if (!treeItem.Expanded)
                    {
                        Mouse.DoubleClick(treeItem);
                        //treeItem.Expanded = true;
                    }
                    ExpandTraverse(treeItem.Nodes.Cast<WpfTreeItem>());
                }
            }
        }

        private static WpfTreeItem GetTreeItem(WpfControl parent, int instance)
        {
            var treeItem = new WpfTreeItem(parent);
            treeItem.SearchProperties[UITestControl.PropertyNames.Instance] =
                instance.ToString(CultureInfo.CurrentCulture);
            treeItem.SearchConfigurations.Add(SearchConfiguration.VisibleOnly);
            treeItem.SearchConfigurations.Add(SearchConfiguration.DisambiguateChild);
            return treeItem;
        }
    }
}
